#include "Ship.h"

using namespace model;

Ship::Ship(void) : Entity()
{
	rotationVelocity = 0;
	maximumVelocity = 0;
	propulsion = 0;
	friction = 0;
	bulletTimeout = 0;
	aceleration = 0;
	currentRotationVelocity = 0;
	rotation = 0.0;
	directionOfVelocity = 0.0;
	life = SHIP_MAX_LIFE;
	numberOfLifes = SHIP_MAX_LIFE_COUNT;
	superShield = NULL;
	shield = NULL;
}

Ship::Ship(int id, const std::string& image, const Point &position, int rotationVelocity,
	int maxVelocity, int propulsion, int friction, int bulletTimeOut)
{
	this->id = id;
	imagePath = image;
	x = position.x();
	y = position.y();
	this->rotationVelocity = rotationVelocity;
	maximumVelocity = maxVelocity;
	this->propulsion = propulsion;
	this->friction = friction;
	bulletTimeout = bulletTimeOut;
	aceleration = 0;
	currentRotationVelocity = 0;
	rotation = 0.0;
	directionOfVelocity = 0.0;
	life = SHIP_MAX_LIFE;
	numberOfLifes = SHIP_MAX_LIFE_COUNT;
	superShield = new SuperShield(this, 38, Point(x-14, y-14));
	shield = new SuperShield(this, 38, Point(x-14, y-14));
	superShield->desable();
	shield->desable();
	
	addFeature(superShield);
	addFeature(shield);
}

Ship::~Ship(void)
{
	delete superShield;
	delete shield;
}

void Ship::initializeFeatures(void)
{
	missiles = 0;
	superShield->desable();
	shield->desable();
	isLaser = false;
	isNeutronBomb = false;
	minesChargeCount = 0;
	isBomb = false;
	isGuidedMissil = false;
	shieldEnergy = 0;
	isGravitationShield = false;
	isGravitationWeapon = false;
}

string Ship::getAcceleratedImagePath(void)
{
	int pos = this->imagePath.find(".");
	string acceleratedPath = this->imagePath.substr(0,pos) + "_on.png";
	return acceleratedPath;
}

void Ship::rotateLeft(void)
{	
	currentRotationVelocity = rotationVelocity;
}

void Ship::rotateRight(void)
{
	currentRotationVelocity = -rotationVelocity;
}

void Ship::acelerate(void)
{
	this->aceleration = this->propulsion;
}

void Ship::updatePositions(double currentTime)
{
	double currentVelocity;	
	double deltaDirection;
	double deltaTime = currentTime - this->currentTime;
	this->currentTime = currentTime;
	double angleDiff = this->directionOfVelocity - this->rotation;

	if (this->isDeadEnabled())
	{
		if (currentTime - this->deadStartTime > DEAD_DURATION)
		{
			this->disableIsDead();
			this->rotation = 0;
			this->setVelocity(0); 
			this->directionModul = 0;
			this->previousRotation = 0;		
		}
	}
	else
	{
		//Agrego el coseno de la diferencia de los angulos de velocidad y rotacion, para q frene al comienzo de la rotacion si no coinciden las direcciones.
		if (isAcelerated()) //Mientras se este acelerando no aplicamos friccion.
		{
			currentVelocity = (this->getVelocity() * cos(angleDiff)) + (deltaTime * (this->aceleration));
		}
		else
		{
			currentVelocity = this->getVelocity() + (deltaTime * (this->aceleration - this->friction));
		}
		if (currentVelocity < 0)
		{
			currentVelocity = 0;
		}
		if (currentVelocity > this->maximumVelocity)
		{
			currentVelocity = this->maximumVelocity;
		}
		
		//dx = (V0 * dt) + 1/2 dt2 * (aceleracion - friccion)
		deltaDirection =  (this->getVelocity() * deltaTime) + (0.5 * pow(deltaTime,2) * (this->aceleration - this->friction));
		if (deltaDirection < 0)
		{
			deltaDirection = 0;
		}
		this->setVelocity(currentVelocity); 
		this->directionModul = deltaDirection;
		this->previousRotation = this->rotation;

		//dAngulo = (360 / Segundos por vuelta) * dt
		if (this->currentRotationVelocity != 0)
		{
			this->rotation += ((360) / this->currentRotationVelocity) * deltaTime;
		}
		if (this->rotation < 0)
		{
			this->rotation = this->rotation + 360;
		}
		if (this->rotation > 360)
		{
			this->rotation = this->rotation - 360;
		}
		if (this->isAcelerated())
		{
			this->directionOfVelocity = this->rotation;
		}
		this->move();

		if (this->isInvisibilityEnabled())
		{
			if (currentTime - this->invisibilityStartTime > INVISIBILITY_DURATION)
			{
				this->disableInvisibility();
			}
		}
	}
}

Polygon* Ship::getPolygon(void)
{
	Polygon* polygon = this->polygon.get();
	if (superShield && superShield->isEnabled())
	{
		polygon = superShield->getPolygon();
	}
	else if (shield && shield->isEnabled())
	{
		polygon = shield->getPolygon();
	}
	return polygon;
}

void Ship::decreaseLife(int powerDamage)
{
	this->life -= powerDamage;
	if (this->life <= 0)
	{
		this->decreaseNumberOfLifes();
		this->life = SHIP_MAX_LIFE;
	}
}

void Ship::decreaseNumberOfLifes(void)
{
	this->numberOfLifes--;
	this->enableIsDead();
	this->life = SHIP_MAX_LIFE; // para que cuando vuelva a generarse otra nave tenga la vida completa
	this->initializeFeatures();
	if (this->numberOfLifes < 0)
	{
		this->numberOfLifes = 0;
	}
}

void Ship::updateFeaturePosition()
{
	vector<Feature*>::iterator itf;
	for (itf=features.begin(); itf!=features.end(); itf++)
	{
		/*if (this->previousRotation != this->rotation)
		{
			(*itf)->getPolygon()->rotate(this->rotation-this->previousRotation);
		}*/

		(*itf)->getPolygon()->moveTo(x-14, y-14);
	}
}

SuperShield* Ship::getSuperShield(void)
{
	return superShield;
}

SuperShield* Ship::getShield(void)
{
	return shield;
}

void Ship::setMines(int count)
{
	minesChargeCount = count;
}

void Ship::setShieldEnergy(int energy)
{
	shieldEnergy = energy;
}

int Ship::getShieldEnergy(void)
{
	return shieldEnergy;
}

void Ship::enableGravitationWeapon(void)
{
	isGravitationWeapon = true;
}

void Ship::disableGravitationWeapon(void)
{
	isGravitationWeapon = false;
}

void Ship::reduceShieldEnery(int powerDamage)
{
	this->shieldEnergy -= powerDamage;
	if (this->shieldEnergy <= 0)
	{
		this->shield->desable();
	}
}
